using System.Collections.Generic;
using System.Threading;

namespace PaulRz.Util.Patterns
{
    /// <summary>
    /// Dictionary implementation of order-insignificant queue. 
    /// The implementation has two queues: acceptor and storage queue.
    /// It supports very fast cleaning with atomic lock.
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    public sealed class StoringQueues<TKey, TValue>
    {
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="capacity">the initial size of queue</param>
        public StoringQueues(int capacity)
        {
            acceptor = new Dictionary<TKey, TValue>(capacity);
            storer = new Dictionary<TKey, TValue>(capacity);
        }

        private object SyncRoot = new object(); 
        private  Dictionary<TKey, TValue> acceptor;
        private  Dictionary<TKey, TValue> storer;

        private void exchangeQueues(ref Dictionary<TKey, TValue> a, ref Dictionary<TKey, TValue> b)
        {
            lock(SyncRoot)
                b = Interlocked.Exchange(ref a, b);
        }

        /// <summary>
        /// Return the size of incoming queue
        /// </summary>
        public int Count
        {
            get
            {
                return acceptor.Count;
            }
        }

        /// <summary>
        /// Get the storing queue
        /// </summary>
        public Dictionary<TKey, TValue> StoringQueue
        {
            get
            {
                return storer;
            }
        }

        /// <summary>
        /// Checks if the key is in the queue
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool IsInQueues(TKey key)
        {
            bool confirmS, confirmA;
            lock(SyncRoot)
            {
                confirmA = acceptor.ContainsKey(key);
                confirmS = storer.ContainsKey(key);
            }
            return confirmA || confirmS;
        }

        /// <summary>
        /// Add a new pair key-value
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Add(TKey key, TValue value)
        {
            lock(SyncRoot)
            {
                acceptor[key] = value;
            }
        }

        /// <summary>
        /// Provide the exchange of queues
        /// </summary>
        public void Exchange()
        {
            exchangeQueues(ref acceptor, ref storer);
        }

        /// <summary>
        /// Clear all content of storing queue
        /// </summary>
        public void ClearStorer()
        {
            lock(SyncRoot)
                storer.Clear();
        }
    }
}
